module OmniVision(
	////////////////////	Clock Input	 	////////////////////	 
	CLK_27,							//	27 MHz
	CLK_50,							//	50 MHz
	////////////////////	DPDT Switch		////////////////////
	SW,								//	Toggle Switch[17:0]
	////////////////////	Push Button		/////////////////////
	KEY,								//	Pushbutton[3:0]
	////////////////////////	LED		/////////////////////
	LEDG,								//	LED Green[8:0]
	LEDR,								//	LED Red[17:0]
	////////////	Camera Interface	/////////////////////////
	CAM_VSYNC,						// CAM V_SYNC
	CAM_HREF,						// CAM HREF
	CAM_PCLK,						// CAM PCLK
	CAM_DATA_UV_RB,				// CAM Data lines UV/RB
	CAM_DATA_Y_G,					// CAM Data lines Y/G
	CAM_RST,							// CAM Reset
	CAM_FODD,						// CAM FODD
	CAM_EXCLK,						// CAM on chip video osc. out
	CAM_PWND,						// CAM power down mode
	CAM_SDA,							// CAM I2C interface data
	CAM_SCL,							// CAM I2C interface clock
	////////////////////	VGA		////////////////////////////
	VGA_CLK,   						//	VGA Clock
	VGA_HS,							//	VGA H_SYNC
	VGA_VS,							//	VGA V_SYNC
	VGA_BLANK,						//	VGA BLANK
	VGA_SYNC,						//	VGA SYNC
	VGA_R,   						//	VGA Red[9:0]
	VGA_G,	 						//	VGA Green[9:0]
	VGA_B,  							//	VGA Blue[9:0]
	////////////////////	SRAM Interface		////////////////
	SRAM_DQ,							//	SRAM Data bus 16 Bits
	SRAM_ADDR,						//	SRAM Address bus 18 Bits
	SRAM_UB_N,						//	SRAM High-byte Data Mask 
	SRAM_LB_N,						//	SRAM Low-byte Data Mask 
	SRAM_WE_N,						//	SRAM Write Enable
	SRAM_CE_N,						//	SRAM Chip Enable
	SRAM_OE_N,						//	SRAM Output Enable
	////////////////////////	UART	////////////////////////
	UART_TXD,						//	UART Transmitter
	UART_RXD,						//	UART Receiver
	////////////////////	7-SEG Dispaly	////////////////////
	HEX							//	Seven Segment
);

////////////////////////	Clock Input	 	////////////////////////
input	CLK_27;							//	27 MHz
input	CLK_50;							//	50 MHz
////////////////////////	DPDT Switch		////////////////////////
input	[17:0] SW;						//	Toggle Switch[17:0]
////////////////////////	Push Button		////////////////////////
input	[3:0]	KEY;						//	Pushbutton[3:0]
////////////////////////////	LED		////////////////////////////
output [8:0] LEDG;				//	LED Green[8:0]
output [17:0] LEDR;				//	LED Red[17:0]
////////////////////////	Camera interface	//////////////////////
input CAM_VSYNC;						// CAM V_SYNC
input CAM_HREF;						// CAM HREF
input CAM_PCLK;						// CAM PCLK
input [7:0] CAM_DATA_UV_RB;		// CAM Data lines UV/RB
input [7:0] CAM_DATA_Y_G;			// CAM Data lines Y/G
output CAM_RST;						// CAM Reset
input CAM_FODD;						// CAM FODD
input CAM_EXCLK;						// CAM on chip video osc. out
output CAM_PWND;						// CAM power down mode
inout CAM_SDA;							// CAM I2C interface data
output CAM_SCL;						// CAM I2C interface clock
////////////////////////	VGA			////////////////////////////
output VGA_CLK;   					//	VGA Clock
output VGA_HS;							//	VGA H_SYNC
output VGA_VS;							//	VGA V_SYNC
output VGA_BLANK;						//	VGA BLANK
output VGA_SYNC;						//	VGA SYNC
output [9:0] VGA_R;   				//	VGA Red[9:0]
output [9:0] VGA_G;	 				//	VGA Green[9:0]
output [9:0] VGA_B;   				//	VGA Blue[9:0]
////////////////////////	SRAM Interface	////////////////////////
inout	[15:0] SRAM_DQ;				//	SRAM Data bus 16 Bits
output [17:0] SRAM_ADDR;			//	SRAM Address bus 18 Bits
output SRAM_UB_N;						//	SRAM High-byte Data Mask
output SRAM_LB_N;						//	SRAM Low-byte Data Mask 
output SRAM_WE_N;						//	SRAM Write Enable
output SRAM_CE_N;						//	SRAM Chip Enable
output SRAM_OE_N;						//	SRAM Output Enable
////////////////////////	UART	////////////////////////
output		UART_TXD;				//	UART Transmitter
input			UART_RXD;				//	UART Receiver
////////////////////////	7-SEG Dispaly	////////////////////////
output[55:0] HEX;
//---------------- INPUT SIDE --------------------------------------

wire RST_N, VGA_MODE;
assign RST_N = KEY[0];
assign CAM_EN = SW[0];
assign UART_Mode = SW[1];
assign VGA_EN = SW[2]; 
assign VGA_MODE = SW[3];

wire CAM_CAPTURE_STOPPED;
wire CAM_IDLE;
wire [18:0] CAM_WR_ADDR;
wire [7:0] CAM_WR_DATA;
wire CAM_WR_CLK;
wire CAM_EN;
wire[9:0] CAM_X,CAM_Y;
CCD_Capture ccd(
	.iVSYNC(CAM_VSYNC),
	.iHREF(CAM_HREF),
	.iPCLK(CAM_PCLK),
	.iFODD(CAM_FODD),
	.iDATA_UV_RB(CAM_DATA_UV_RB),
	.iDATA_Y_G(CAM_DATA_Y_G),
	.oRST(CAM_RST),
	.oPWND(CAM_PWND),
	.X_Count(CAM_X),
	.Y_Count(CAM_Y),
	.oWR_DATA(CAM_WR_DATA),
	.oWR_ADDR(CAM_WR_ADDR),
	.oWR_CLK(CAM_WR_CLK),
	.iCAPTURE_EN(CAM_EN),
	.oCAPTURE_STOPPED(CAM_CAPTURE_STOPPED),
	.oIDLE(CAM_IDLE)
);

I2C_CAM_Config i2c(
	.iCLK(CLK_50),
	.iRST_N(RST_N),
	.I2C_SCLK(CAM_SCL),
	.I2C_SDAT(CAM_SDA)
);

wire [18:0] SRAM_ADDRESS;
wire [7:0] SRAM_ODATA;
wire [7:0] SRAM_IDATA;
wire SRAM_OE_N;
wire SRAM_WE_N;
wire SRAM_CE_N;
RAM_SRAM sram(		//256K x 16
	.iDATA(SRAM_IDATA),
	.iADDR(SRAM_ADDRESS),
	.iWE_N(SRAM_WE_N),
	.oDATA(SRAM_ODATA),
	.iOE_N(SRAM_OE_N),
	.iCE_N(SRAM_CE_N),
	.SRAM_DQ(SRAM_DQ),
	.SRAM_ADDR(SRAM_ADDR),
	.SRAM_UB_N(SRAM_UB_N),
	.SRAM_LB_N(SRAM_LB_N),
	.SRAM_WE_N(SRAM_WE_N),
	.SRAM_CE_N(SRAM_CE_N),
	.SRAM_OE_N(SRAM_OE_N)
);

assign {SRAM_ADDRESS, SRAM_IDATA, SRAM_CE_N, SRAM_WE_N, SRAM_OE_N} = 
	(UART_BUSY & UART_Mode) ? {UART_Address, UART_Data[7:0], 1'b0, UART_WEN, 1'b1} :
	(~CAM_CAPTURE_STOPPED & ~CAM_IDLE) ? {CAM_WR_ADDR, 8'bz, 1'b0, 1'b1, ~CAM_WR_CLK}:
	VGA_MODE ? {mVGA_ADDR,8'dz,1'b0,1'b1,(mVGA_oR_EN & VGA_CLK)}:
	{27'bz, 3'b111};
	
//---------------- FUNCTION --------------------------------------
wire[401:0] CR_Result;
wire[19:0] CR_Status;
CamReaderCW cr(
	.iPCLK(CAM_WR_CLK),
	.iCLK(CLK_50),
	.iData(SRAM_ODATA),
	.iX(CAM_X),  //CAM_X
	.iY(CAM_Y),	 //CAM_Y
	.iFrame(~CAM_IDLE),
	.oDebug(CR_Result),
	.oStatus(CR_Status),
	.iRST(~RST_N),
	.oTrigStart(TrigStart),
	.oTrigFunc(TrigFunc),
	.iTrigBusy(TrigBusy),
	.iTrigError(TrigError),
	.oTrigData(TrigData),
	.iTrigResult(TrigResult),
	.oTXD(UART_TXD),
	.iTXStart(~KEY[1])
);

wire TrigStart, TrigBusy, TrigError;
wire[1:0] TrigFunc;
wire[31:0] TrigData;
wire[31:0] TrigResult;
TrigonometricFunc trig(
	.iRST_N(RST_N),
	.iCLK(~CLK_50),
	.iStartProcess(TrigStart),
	.iFunc(TrigFunc),
	.oBusy(TrigBusy),
	.oError(TrigError),
	.iData(TrigData),
	.oData(TrigResult)
);

wire[9:0] VGA_X, VGA_Y;
assign VGA_X = mVGA_ADDR % 10'd640;
assign VGA_Y = mVGA_ADDR / 10'd640;
wire[3:0] FrameRamQ;
//FrameRam fram(
//	.data(CAM_DATA_Y_G[7:4]),
//	.rdaddress(VGA_Y[9:2] * 160 + VGA_X[9:2]),
//	.rdclock(~(mVGA_oR_EN & VGA_CLK)),
//	.wraddress(CAM_Y[9:2] * 160 + CAM_X[9:2] - 1),
//	.wrclock(~CAM_WR_CLK),
//	.wren(~CAM_CAPTURE_STOPPED & ~CAM_IDLE),
//	.q(FrameRamQ));
	
//---------------- DEBUG SIDE --------------------------------------

assign LEDR = {CR_Status};
assign LEDG = {blink, 6'd0 ,TrigError,TrigBusy};
assign seg7 = 
	SW[17:14] == 4'd0 ? CR_Result[31:0] :		// MultA
	SW[17:14] == 4'd1 ? CR_Result[63:32] :		// MultB
	SW[17:14] == 4'd2 ? CR_Result[95:64] :		// MultARes
	SW[17:14] == 4'd3 ? CR_Result[127:96] :	// SinglePrecFloatSqrtA
	SW[17:14] == 4'd4 ? CR_Result[159:128] :	// SinglePrecFloatSqrtRes
	SW[17:14] == 4'd5 ? CR_Result[191:160] :	// ~IntToFP1A
	SW[17:14] == 4'd6 ? CR_Result[223:192] :	// ~IntToFP1Res
	SW[17:14] == 4'd7 ? CR_Result[255:224] :	// Add1A
	SW[17:14] == 4'd8 ? CR_Result[287:256] :	// Add1B
	SW[17:14] == 4'd9 ? CR_Result[309:288] :	// Add1Res
	SW[17:14] == 4'd10 ? TrigData :
	SW[17:14] == 4'd11 ? TrigResult :
	SW[17:14] == 4'd12 ? {6'd0,CR_Result[401:376]} :
	SW[17:14] == 4'd13 ? CR_Result[337:310] :	CR_Result[375:338];	// fifo_out, fifo_in;

always@(posedge UART_SEND_BUSY)begin
	if(UART_SEND_BUSY)
		UART_SEND_START <= 1'b0;
	else
		UART_SEND_START <= 1'b1;
end

VGA_PLL pll25 (
	.inclk0(CLK_27),
	.c0(VGA_CLK_25_2)
);

wire [18:0]	mVGA_ADDR;
wire [18:0]	mVGA_ADDRCropped;
wire mVGA_oR_EN;
wire mVGA_oR_ENCropped;
wire VGA_CLK_25_2;
wire VGA_RST_N;
assign VGA_RST_N = RST_N;
wire VGA_EN;
//assign VGA_EN = ~UART_BUSY & (CAM_CAPTURE_STOPPED || CAM_IDLE);
VGA_Controller	vga	(
	.iRST_N(VGA_RST_N),
	//.iData(SRAM_ODATA),
	.iData(VGA_MODE ? SRAM_ODATA : {FrameRamQ, 4'b0}),
	.oAddress(mVGA_ADDR),
	.oAddressCropped(mVGA_ADDRCropped),
	.oR_EN(mVGA_oR_EN),
	.oR_ENCropped(mVGA_oR_ENCropped),
	.oVGA_R(VGA_R),
	.oVGA_G(VGA_G),
	.oVGA_B(VGA_B),
	.oVGA_HS(VGA_HS),
	.oVGA_VS(VGA_VS),
	.oVGA_SYNC(VGA_SYNC),
	.oVGA_BLANK(VGA_BLANK),
	.oVGA_CLOCK(VGA_CLK),
	.iCLK(VGA_CLK_25_2),
	.iEN(VGA_EN)
);

wire UART_BUSY, UART_WEN;
wire[63:0] UART_Data;
wire[18:0] UART_Address;
wire UART_Mode;
UART_Recieve uart_rec(
	.iRST_N(RST_N),
	.iRX(UART_RXD),
	.iCLK(CLK_50),
	.iMode(UART_Mode),
	.oBUSY(UART_BUSY),
	.oDATA(UART_Data),
	.oADDR(UART_Address),
	.oWE_N(UART_WEN)
);

wire UART_SEND_BUSY;
reg UART_SEND_START;
wire [31:0] UART_SEND_DATA;
UART_Sender uart_send(
	.oTX(),
	.iSTART(UART_SEND_START),
	.iDATA(UART_SEND_DATA),
	.oBUSY(UART_SEND_BUSY),
	.iCLK(CLK_50),
	.iRST_N(RST_N)
);

wire [31:0] seg7;
SEG7_LUT_8 seg(	
	.oSEG0(HEX[6:0]),
	.oSEG1(HEX[13:7]),
	.oSEG2(HEX[20:14]),
	.oSEG3(HEX[27:21]),
	.oSEG4(HEX[34:28]),
	.oSEG5(HEX[41:35]),
	.oSEG6(HEX[48:42]),
	.oSEG7(HEX[55:49]),
	.iDIG(seg7) 
);

reg blink;
reg[31:0] counter;
always@(posedge CLK_50)
begin
	if(counter < 25000000)
		counter <= counter + 1;
	else begin
		counter <= 0;
		blink <= ~blink;
	end
end

endmodule
